package com.apes.fn.fico.reimbursement.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.fico.reimbursement.model.*;
import com.apes.fn.fico.reimbursement.repository.DebitRepaymentRepository;
import com.apes.fn.fico.reimbursement.repository.ExpenseDebitRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.Tools;
import com.apes.hr.base.model.Employee;
import com.apes.hr.base.repository.EmployeeRepository;
import com.apes.hr.base.repository.WorkPostRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.PostRepository;
import com.apes.scm.rbac.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 借支还款
 * Created by lishikun on 2021/2/1 15:44
 */
@Service("debitRepaymentService")
public class DebitRepaymentService extends DomainService {
    @Autowired
    DebitRepaymentRepository debitRepaymentRepository;

    @Autowired
    ExpenseDebitRepository expenseDebitRepository;

    @Autowired
    SequenceService sequenceService;
    @Autowired
    PostRepository postRepository;

    public DebitRepayment create(SimpleRequest request) {
        DebitRepayment debitRepayment = request.getO(DebitRepayment.class);
        //按需求所说 岗位为空时取操作员的人员档案中的岗位
        Optional.ofNullable(request.getPerson()).ifPresent(person -> {
            Employee employee = SpringManager.getBean(EmployeeRepository.class).findByParty(((PartyRole) person).getParty());
            if (!Tools.isNull(employee)) {
                debitRepayment.setWorkPost(employee.getPost());
            }
        });
        Post post = postRepository.findOne(request.getPostId());
        debitRepayment.setCompany(post.getCompany());
        DebitRepayment repayment = checkDebitRepayment(debitRepayment);
        // 修改费用借支单的数据
        checkDebit(debitRepayment);
        return repayment;
    }

    /**
     * 检查借支
     *
     * @param debitRepayment
     */
    public void checkDebit(DebitRepayment debitRepayment) {
        debitRepayment.getDebitRepaymentItems().forEach(debitRepaymentItem -> {
            ExpenseDebit expenseDebit = debitRepaymentItem.getExpenseDebit();
            if (expenseDebit.getPendingSum() == 0) {
                throw new RuntimeException(String.format("借支单%s已还款！请检查借支单与还款单！建议重新发起审批", expenseDebit.getId()));
            }
            // 设置费用还款单的还款金额，来源单据，来源类型
            ExpenseRepaymentItem expenseRepaymentItem = new ExpenseRepaymentItem();
            expenseRepaymentItem.setId(SpringManager.getBean(SequenceService.class).getId(expenseRepaymentItem.CONST_TABLE_NAME));
            expenseRepaymentItem.setRepaymentMoney(debitRepaymentItem.getAmountRepayment());
            expenseRepaymentItem.setSource(debitRepayment.getId());
            expenseRepaymentItem.setSourceBusinessType(debitRepayment.getInnerBusinessType());
            expenseRepaymentItem.setExpenseDebit(expenseDebit);
            expenseRepaymentItem.setRemark(debitRepayment.getRemark());
            expenseRepaymentItem.setState("sent");
            expenseDebit.getExpenseRepaymentItems().add(expenseRepaymentItem);
            expenseDebit.computeAmt();
            expenseDebitRepository.saveAndFlush(expenseDebit);
        });
    }


    /**
     * 借支还款记录归零
     *
     * @param debitRepayment
     */
    public void zeroDebitItem(DebitRepayment debitRepayment) {
        debitRepayment.getDebitRepaymentItems().forEach(debitRepaymentItem -> {
            ExpenseDebit expenseDebit = debitRepaymentItem.getExpenseDebit();
            expenseDebit.getExpenseRepaymentItems().stream().filter(expenseRepaymentItem -> Objects.equals(expenseRepaymentItem.getSource(),debitRepayment.getInnerBusinessKey())).findFirst().ifPresent(expenseRepaymentItem -> {
                expenseRepaymentItem.setRepaymentMoney(0);
                expenseRepaymentItem.setState("delete");
                expenseRepaymentItem.setRemark(expenseRepaymentItem.getRemark()+"——还款单已删除");
            });

            expenseDebit.setState("repayment");
            expenseDebit.computeAmt();
            expenseDebitRepository.saveAndFlush(expenseDebit);
        });
    }

    /**
     * 检查并保存
     * @param debitRepayment
     * @return
     */
    public DebitRepayment checkDebitRepayment(DebitRepayment debitRepayment) {
        debitRepayment.getDebitRepaymentItems().forEach(debitRepaymentItem -> {
            if (debitRepaymentItem.getBalance() != 0) {
                if (Tools.isNull(debitRepaymentItem.getPayPeople()) || Tools.isNull(debitRepaymentItem.getAccountBank()) || Tools.isNull(debitRepaymentItem.getAccountBankName())
                        || Tools.isNull(debitRepaymentItem.getAccountBankNumber()) || Tools.isNull(debitRepaymentItem.getSubbranch())) {
                    throw new RuntimeException("待付款金额不为0时，支付人，收款账户名称，账号，开户行，支行必填");
                }
            }
            debitRepaymentItem.getRepaymentInvoiceItems().forEach(typeItem->{
                if(typeItem.getInvoice().getDescription().equals("专票")) {
                    if (Tools.isNull(typeItem.getInvoiceNumber()) || Tools.isNull(typeItem.getPriceTax())|| Tools.isNull(typeItem.getTax()) )
                        throw new RuntimeException("专票：发票号码、价税合计金额、税率,为必填");
                }
            });
        });
        return debitRepaymentRepository.saveAndFlush(debitRepayment);
    }

    public DebitRepayment update(SimpleRequest request) {
        DebitRepayment debitRepayment = request.getO(DebitRepayment.class);
        DebitRepayment repayment = checkDebitRepayment(debitRepayment);
        zeroDebitItem(debitRepaymentRepository.findOne((String) request.get("id")));
        repayment.getDebitRepaymentItems().forEach(debitRepaymentItem -> {
            ExpenseDebit expenseDebit = debitRepaymentItem.getExpenseDebit();
            ExpenseRepaymentItem repaymentItem = expenseDebit.getExpenseRepaymentItems().stream().filter(expenseRepaymentItem -> Objects.equals(expenseRepaymentItem.getSource(), debitRepayment.getInnerBusinessKey())).findFirst().orElse(null);
            if (repaymentItem == null) {
                // 设置费用还款单的还款金额，来源单据，来源类型
                ExpenseRepaymentItem expenseRepaymentItem = new ExpenseRepaymentItem();
                expenseRepaymentItem.setId(SpringManager.getBean(SequenceService.class).getId(expenseRepaymentItem.CONST_TABLE_NAME));
                expenseRepaymentItem.setRepaymentMoney(debitRepaymentItem.getAmountRepayment());
                expenseRepaymentItem.setSource(repayment.getId());
                expenseRepaymentItem.setSourceBusinessType(repayment.getInnerBusinessType());
                expenseRepaymentItem.setExpenseDebit(expenseDebit);
                expenseRepaymentItem.setRemark(repayment.getRemark());
                repaymentItem.setState("sent");
                expenseDebit.getExpenseRepaymentItems().add(expenseRepaymentItem);
            }else {
                if (expenseDebit.getPendingSum() == 0) {
                    throw new RuntimeException(String.format("借支单%s已还款！请检查借支单与还款单！建议重新发起审批", expenseDebit.getId()));
                }
                repaymentItem.setRemark(repayment.getRemark());
                repaymentItem.setState("sent");
                repaymentItem.setRepaymentMoney(repaymentItem.getRepaymentMoney()+debitRepaymentItem.getAmountRepayment());
            }
            expenseDebit.computeAmt();
            expenseDebitRepository.saveAndFlush(expenseDebit);
        });
        return repayment;
    }

    public DebitRepayment refuse(SimpleRequest request) {
        DebitRepayment debitRepayment = request.getO(DebitRepayment.class);
        debitRepayment.setState("create");
        return checkDebitRepayment(debitRepayment);
    }

    public DebitRepayment cashier(SimpleRequest request) {
        DebitRepayment debitRepayment = request.getO(DebitRepayment.class);
        debitRepayment.setState("cashier");
        return checkDebitRepayment(debitRepayment);
    }


    public DebitRepayment finish(SimpleRequest request) {
        DebitRepayment debitRepayment = request.getO(DebitRepayment.class);
        debitRepayment.setState("finish");
        debitRepayment.getDebitRepaymentItems().forEach(debitRepaymentItem -> {
            ExpenseDebit expenseDebit = debitRepaymentItem.getExpenseDebit();
            expenseDebit.getExpenseRepaymentItems().stream().filter(expenseRepaymentItem -> Objects.equals(expenseRepaymentItem.getSource(),debitRepayment.getInnerBusinessKey())).findFirst().ifPresent(expenseRepaymentItem -> {
                expenseRepaymentItem.setState("done");
            });
            if (expenseDebit.getPendingSum() == 0 && expenseDebit.getExpenseRepaymentItems().stream().allMatch(expenseRepaymentItem -> Objects.equals("done", expenseRepaymentItem.getState()))) {
                expenseDebit.setState("finish");
            }
            expenseDebit.computeAmt();
            expenseDebitRepository.saveAndFlush(expenseDebit);
        });

        return checkDebitRepayment(debitRepayment);
    }

    public String delete(SimpleRequest request) {
        DebitRepayment debitRepayment = request.getO(DebitRepayment.class);
        zeroDebitItem(debitRepayment);
        debitRepaymentRepository.delete(debitRepayment);
        return "删除成功";
    }

    public DebitRepayment approve(SimpleRequest request) {
        DebitRepayment debitRepayment = request.getO(DebitRepayment.class);
        debitRepayment.setApproveId(this.getPerson(request));
        debitRepayment.setApproveDate(new Date());
        debitRepayment.setState("approve");
        setSupperOA(debitRepayment);
        inspectionFeeType(debitRepayment,debitRepayment.getDebitRepaymentItems().stream().findFirst().get().getExpenseDebit().getFeeType().getCode());
        debitRepayment.getDebitRepaymentItems().forEach(debitRepaymentItem -> {
            ExpenseDebit expenseDebit = debitRepaymentItem.getExpenseDebit();
            expenseDebit.getExpenseRepaymentItems().stream().filter(expenseRepaymentItem -> Objects.equals(expenseRepaymentItem.getSource(),debitRepayment.getInnerBusinessKey())).findFirst().ifPresent(expenseRepaymentItem -> {
                expenseRepaymentItem.setState("approve");
            });
            expenseDebit.computeAmt();
            expenseDebitRepository.saveAndFlush(expenseDebit);
        });
        return debitRepaymentRepository.saveAndFlush(debitRepayment);
    }

    /**
     * 生成还款单
     *
     * @param request
     * @return
     */
    public DebitRepayment generate(SimpleRequest request) {
        //处理传参
        JSONArray parameter = request.get("parameter");
        DebitRepayment debitRepayment = new DebitRepayment();
        List<DebitRepaymentItem> debitRepaymentItems = new ArrayList<>();
        //处理明细
        parameter.forEach(data -> {
            String debitId = ((JSONObject) data).getString("id");
            //获取借支信息
            ExpenseDebit expenseDebit = expenseDebitRepository.findOne(debitId);
            //填充还款明细
            DebitRepaymentItem debitRepaymentItem = new DebitRepaymentItem();
            debitRepaymentItem.setExpenseDebit(expenseDebit);
//            debitRepaymentItem.setDutyCenter(expenseDebit.getDutyCenter());
            debitRepaymentItem.setDebitAmount(expenseDebit.getPendingSum());
            debitRepaymentItem.setAmountRepayment(expenseDebit.getPendingSum());
            debitRepaymentItem.setBalance(Arith.sub(debitRepaymentItem.getDebitAmount(), debitRepaymentItem.getAmountRepayment()));
            debitRepaymentItems.add(debitRepaymentItem);
        });
        debitRepayment.setDebitRepaymentItems(debitRepaymentItems);
        return debitRepayment;
    }


    /**
     * 按需求完全复制报销 与借支的OA流程  此处未做任何更改
     *
     * @param debitRepayment
     */
    private void setSupperOA(DebitRepayment debitRepayment) {
        // 控制父类审批
        String code = debitRepayment.getDebitRepaymentItems().stream().findFirst().get().getExpenseDebit().getFeeType().getCode();
        String id = SpringManager.getBean(WorkPostRepository.class).findOne(debitRepayment.getWorkPost().getId()).getParents().getId();
        String workPostId = debitRepayment.getWorkPost().getId();
        if ("0000016".equals(workPostId)) {
            debitRepayment.setNeedSupperOA("1");
            return;
        }
        if ("0000187".equals(id) && "DecorationCost".equals(code)) debitRepayment.setNeedSupperOA("1");     // 上级岗位
        else if ("0000095".equals(id) && "FinanceCost".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000105".equals(id) && "BusinessExpenses".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000080".equals(id) && "UnionType".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000172".equals(id) && "CustomerFee".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000115".equals(id) && "InfoCost".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000044".equals(id) && "PurchasingCost1".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000043".equals(id) && "Logistics".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000027".equals(id) && "DoorPipe".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000109".equals(id) && "DataType".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000140".equals(id) && "OperationsCenter".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000191".equals(id) && "Burst".equals(code)) debitRepayment.setNeedSupperOA("1");
        else if ("0000822".equals(id) && "Training".equals(code)) debitRepayment.setNeedSupperOA("1");
        else debitRepayment.setNeedSupperOA("0");


    }

    /**
     * 检验费用类型
     * @param debitRepayment
     * @param feeTypeCode
     */
    private void inspectionFeeType(DebitRepayment debitRepayment, String feeTypeCode) {
        switch (feeTypeCode) {
            //信息类费用
            case "InfoCost":
                assignmentCandidates(debitRepayment, "0000115");
                break;

            //商务类费用
            case "BusinessExpenses":
                assignmentCandidates(debitRepayment, "0000105");
                break;

            //客服类费用
            case "CustomerFee":
                assignmentCandidates(debitRepayment, "0000172");
                break;

            //采购类费用(外协不得垫付后报销)
            case "PurchasingCost1":
                assignmentCandidates(debitRepayment, "0000044");
                break;

            //采购类（设备维修）费用
            case "PurchasingCost2":
                debitRepayment.setCandidates(JSON.toJSONString(Arrays.asList("305","958")));
                break;

            //装修类费用
            case "DecorationCost":
                assignmentCandidates(debitRepayment, "0000187");
                break;

            //财务类费用
            case "FinanceCost":
                assignmentCandidates(debitRepayment, "0000095");
                break;

            //行政类费用
            case "Administrative":
                //工会类费用
            case "UnionType":
                assignmentCandidates(debitRepayment, "0001072");
                break;

            //物流类费用
            case "Logistics":
                assignmentCandidates(debitRepayment, "0000043");
                break;

            //门管技术类费用
            case "DoorPipe":
                assignmentCandidates(debitRepayment, "0000027");
                break;

            //数据类费用
            case "DataType":
                assignmentCandidates(debitRepayment, "0000109");
                break;

            //市场中心类
            case "Market":

                //运营中心费用
            case "OperationsCenter":
                assignmentCandidates(debitRepayment, "0000140");
                break;

            //连发类费用
            case "Burst":
                assignmentCandidates(debitRepayment, "0000079");
                break;

            //培训类费用
            case "Training":
                assignmentCandidates(debitRepayment, "0000822");
                break;

            //人资类费用
            case "HumanResources":
                assignmentCandidates(debitRepayment, "0001232");
                break;

            //证券法务类费用
            case "SecuritiesLegalAffairs":
                assignmentCandidates(debitRepayment, "0001229");
                break;

            //SAAS研发类费用
            case "S006500":
                assignmentCandidates(debitRepayment, "0000140");
                break;
            //品牌部费用
            case "BrandType":
                assignmentCandidates(debitRepayment, "0001272");
                break;

            default:
                throw new RuntimeException("当前费用类型未定义待办岗位！无法发起OA");
        }
    }

    /**
     *  设置各类费用审批主管
     * @param debitRepayment
     * @param postId
     */
    private void assignmentCandidates(DebitRepayment debitRepayment, String postId) {
        List<Post> posts = postRepository.findAllByWorkPostId(postId);
        List<User> agents = new ArrayList<>();
        if (!posts.isEmpty()){
            posts.forEach(post -> {
                List<User> users = SpringManager.getBean(UserRepository.class).findByPost(post.getId());
                if (!users.isEmpty()) agents.addAll(users);
            });
        }
        if(!agents.isEmpty()) {
            List<String> users = new ArrayList<>();
            agents.stream().distinct().forEach(agent -> {
                users.add(String.valueOf(agent.getId()));
            });
            debitRepayment.setCandidates(JSONObject.toJSONString(users));
        }
    }
}
